// Copyright 1998-2016 Glenn McIntosh
// licensed under the GNU General Public Licence version 3
#pragma once

/** @file quaternion.h
	Quaternion arithmetic and conversions
	*/

// include files
#include <vector>
#include "matrix.h"

namespace math
{
/** real type */
using real = double;

/** Quaternion. */
class Quaternion
{
public:
	/** construct a zero quaternion */
	Quaternion()
	{
		w = 1;
		x = y = z = 0;
	}

	/** construct an initialized quaternion */
	Quaternion(real _w, real _x, real _y, real _z)
	{
		w = _w;
		x = _x;
		y = _y;
		z = _z;
	}

	/** construct a quaternion from axis angles
		@param roll angle around forward axis
		@param pitch angle around cross axis
		@param yaw angle around up/down axis
		@result quaternion
		*/
	Quaternion(real roll, real pitch, real yaw);

	/** construct axis angles from a quaternion
		@return axis angles
		*/
	operator Array<3>() const;

	/** construct a quaternion from a rotation matrix
		@param m matrix to be converted
		The resultant quaternion is not normalized.
		*/
	Quaternion(const Matrix<3,3> &m);

	/** convert a quaternion to a rotation matrix
		@return rotation matrix
		The quaternion need not be normalized first.
		*/
	operator Matrix<3,3>() const;

	/** convert a quaternion to Euler angles
		@return Euler angles (roll, pitch, yaw)
		*/
	Array<3> euler() const;

	/** conjugate a quaternion */
	Quaternion operator-() const
	{
		return Quaternion(w, -x, -y, -z);
	}

	/** multiply a quaternion */
	Quaternion operator*(const Quaternion &b) const;

	/** rotate a vector */
	Array<3> rotate(const Array<3> &b) const;

public:
	//@{
	/** components */
	real w, x, y, z;
	//@}
};

/** Normalize a rotation matrix.
	@param m matrix to be normalized in-place
	*/
Matrix<3,3> normalizeRotationMatrix(const Matrix<3,3> &m);
}
